package com.spx.core.types;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToMany;
import javax.persistence.Query;
import javax.persistence.Table;

import com.spx.kernel.service.PersistService;
import com.spx.kernel.types.AbstractModelType;

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "USERS")
public class User extends AbstractModelType
{

	static final String EMAIL_REGEX = "(\\w+)@(\\w+\\.)(\\w+)(\\.\\w+)*";

	// @Type(type="locale")
	// private Locale locale;

	@ManyToMany
	Set<Role> roles;

	/**
	 * email address of user
	 */
	private String emailAddress;
	/**
	 * The number of invalid login attempts since the last successful one
	 */
	private Integer invalidLoginAttempts;
	/**
	 * The encrypted password
	 */
	private String password;

	/**
	 * The ID of the current session (system maintained)
	 */
	protected String sessionID;
	/**
	 * Is the user temporarily disabled?
	 */
	@Column(columnDefinition = "BOOLEAN")
	protected boolean disabled = false;

	/**
	 * Is the user Disabled
	 * 
	 * @return true if the user cannot login
	 */
	public boolean isDisabled()
	{
		return disabled;
	}

	public void setDisabled(boolean disabled)
	{
		this.disabled = disabled;
	}

	/**
	 * Date/Time this user last logged in
	 */
	private Date lastLogin = new Date();

	public User()
	{
		super();
	}

	/**
	 * email address of user
	 */
	public String getEmailAddress()
	{
		return this.emailAddress;
	}

	/**
	 * email address of user
	 */
	public boolean setEmailAddress(final String emailAddress)
	{
		boolean done = false;
		if (emailAddress.matches(EMAIL_REGEX))
		{
			this.emailAddress = emailAddress;
			done = true;
		} else
		{
			// /
		}
		return done;
	}

	//
	// public void setLocale(Locale locale)
	// {
	// this.locale = locale;
	// }
	//
	// public Locale getLocale()
	// {
	// return locale;
	// }

	/**
	 * The number of invalid login attempts since the last successful one
	 */
	public Integer getInvalidLoginAttempts()
	{
		return this.invalidLoginAttempts;
	}

	/**
	 * The number of invalid login attempts since the last successful one
	 */
	public void setInvalidLoginAttempts(final Integer invLoginAttmpt)
	{
		this.invalidLoginAttempts = invLoginAttmpt;
	}

	/**
	 * The encrypted password
	 */
	public String getPassword()
	{
		return this.password;
	}

	/**
	 * The encrypted password
	 */
	public void setPassword(final String password)
	{
		this.password = password;
	}

	/**
	 * Date/Time this user last logged in
	 */
	public Date getLastLogin()
	{
		return this.lastLogin;
	}

	/**
	 * Date/Time this user last logged in
	 */
	public void setLastLoginDate(final Date lastLogin)
	{
		this.lastLogin = lastLogin;
	}

	@SuppressWarnings("unchecked")
	public static User login(final String userName, final String password)
	{
		final PersistService peristence = com.spx.kernel.KernelActivator.getDefault().getPersistService();
		final EntityManager em = peristence.getEntityManager();
		final Query query = em.createQuery("select u from " + User.class.getName() + " u where  u.name = :name and u.password = :password");
		query.setParameter("name", userName);
		query.setParameter("password", password);

		final List<User> users = query.getResultList();

		User user = null;
		if (users.isEmpty() == false)
		{
			user = users.get(0);
			user.setLastLoginDate(new Date());
			em.merge(user);
		}
		return user;

	}

	public Set<Role> getRoles()
	{
		if (roles == null)
		{
			roles = new HashSet<Role>();
		}

		return roles;
	}

	public void remove(Role role)
	{
		getRoles().remove(role);
	}

	public boolean canPerform(String actionName)
	{
		boolean result = false;
		for (final Role role : roles)
		{
			if (role.canPerform(actionName))
			{
				result = true;
				break;
			}
		}
		return result;
	}

	public void add(Role role)
	{
		getRoles().add(role);
	}

	public void setRoles(Set<Role> newRoles)
	{
		getRoles().addAll(newRoles);
		getRoles().retainAll(newRoles);
	}

}